//
//  @ Project : Galaxy Star Trading System
//  @ File Name : Indicator.cpp
//  @ Date : 2014/9/5
//  @ Author :
//
//


#include "../StdInc.h"

namespace GSTrader
{
	namespace Indicator
	{
		CIndicator::CIndicator(CSeries* pInput) : m_bAutoUpdate(true), m_bCalc(true)
		{
			m_pInput = pInput;
			m_pInput->m_lIndicator.push_back(this);

			m_pResult = new CIndicatorResult;
			m_vResult.push_back(m_pResult);
		}

		CIndicator::CIndicator() : m_bAutoUpdate(true), m_bCalc(true)
		{
			m_pInput = NULL;

			m_pResult = new CIndicatorResult;
			m_vResult.push_back(m_pResult);
		}

		CIndicator::CIndicator(const CIndicator& indi)
		{
			m_pInput = indi.m_pInput;
			m_pResult = new CIndicatorResult(*indi.m_pResult);
			m_vResult.push_back(m_pResult);

		}

		CIndicator::~CIndicator()
		{
			for (size_t x = 1; x < m_vResult.size(); x++)
			{
				_delete(m_vResult[x]);
			}

			m_vResult.clear();
		}

		void CIndicator::Attach()
		{
			m_pInput->AddIndicator(this);
		}

		void CIndicator::Detach()
		{
			m_pInput->RemoveIndicator(this);
		}

		void CIndicator::SetParam(double* pdParam)
		{

		}

		void CIndicator::RemoveFirst()
		{
			assert(false); 
		}

		void CIndicator::Clear()
		{
			m_bCalc = true;
			m_pInput = NULL;
			for (size_t x = 0; x < m_vResult.size(); x++)
			{
				m_vResult[x]->Clear();
			}
		}

		void CIndicator::SetInputSeries(CSeries* pSeries)
		{
			int nOldCount = 0;

			if (m_pInput &&  m_pInput != pSeries)
			{
				Clear();
			}

			if (m_pInput)
			{
				nOldCount = m_pInput->GetCount();
			}

			m_pInput = pSeries;

			if (m_pInput)
			{
				int nStartIndex = pSeries->m_nStartIndex;
				bool bSetStartIndex = false;
				if (nStartIndex >= 0)
				{
					size_t x = m_vResult.size();
					for (auto p : m_vResult)
					{
						if (p->m_pDataSeries->m_nStartIndex < 0)
						{
							bSetStartIndex = true;
							break;
						}
					}
				}
				

				int nCount = m_pInput->GetCount();
				if (bSetStartIndex || nOldCount == 0 || abs(nCount - nOldCount) > 1)
				{
					RefreshData();
				}
			}
		}

		double CIndicator::GetResultValueByName(string strResultName, int nDataIndex)
		{
			if (strResultName.empty())
				return _DBL_NAN;

			for (size_t x = 0; x < m_vResult.size(); x++)
			{
				CIndicatorResult* pResult = m_vResult[x];
				if (pResult->m_strName == strResultName)
				{
					return GetResultValue(x, nDataIndex);
				}
			}

			return _DBL_NAN;
		}

		double CIndicator::GetResult(int nIndex)
		{
			size_t x = m_vResult.size();
			if (x < 1)
				return _DBL_NAN;

			CIndicatorResult* pResult = m_vResult[0];
			return pResult->GetValue(nIndex);
		}

		double CIndicator::GetResultValue(int nResultIndex, int nDataIndex)
		{
			if (nResultIndex < 0 || nResultIndex >= (int)m_vResult.size())
				return _DBL_NAN;

			CIndicatorResult* pResult = m_vResult[nResultIndex];
			return pResult->GetValue(nDataIndex);
		}

		void CIndicator::RefreshData()
		{

		}

		int CIndicator::GetCount()
		{
			if (m_pInput)
			{
				return m_pInput->GetCount();
			}

			return 0;
		}

		string CIndicator::GetIndicatorName()
		{
			return m_strIndicatorName;
		}


		void CIndicator::Calculate()
		{
			if (m_pInput == NULL)
				return;

L1:
			if (m_bCalc)
			{
				m_bCalc = false; 
				CIndicator* pIndicator = dynamic_cast<CIndicator*>(m_pInput);
				if (pIndicator)
				{
					pIndicator->Calculate();
				}

				for (int x = 0; x < m_pInput->GetCount(); x++)
				{
					InternalCalculate(x);
				}
			}
			else 
			{
				int nLastIndex = m_pInput->GetCount() - 1;
				if (nLastIndex < 0)
					return;

				size_t x = m_vResult.size();
				if (x > 0)
				{
					CIndicatorResult* pResult = m_vResult[0];
					int nCount = pResult->m_pDataSeries->GetCount();
					if (nCount < nLastIndex)
					{
						m_bCalc = true;
						goto L1;
					}
				}

				CIndicator* pIndicator = dynamic_cast<CIndicator*>(m_pInput);
				if (pIndicator)
				{
					pIndicator->Calculate(nLastIndex);
				}

				Calculate(nLastIndex);
			}
		}

		double CIndicator::Calculate(int nIndex)
		{
			return 0;
		}

		void CIndicator::InternalCalculate(int nIndex)
		{
			if (m_bCalc)
			{
				Calculate();
			}
			else
			{
				Calculate(nIndex);
			}
		}
	}
}